<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 一句话介绍call()
        // call()方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法
        // 举个例子
        // var foo = {
        //     value:1
        // }
        // function bar() {
        //     console.log(this.value)
        // }
        // bar.call(foo)
        // 1.call改变了this指向，指向了foo
        // 2.bar函数执行了

        // 模拟实现第一步
        // var foo = {
        //     value:1,

        // }    
        // function bar() {
        //         console.log(this.value)
        // }
        // 这个时候this就指向了foo,当时却给foo添加了一个属性，这样可不行
        // 我们可以用delete删除掉
        // 模拟步骤分为
        // 1.将函数设为对象的属性
        // 2.执行该函数
        // 3.删除该函数
        // foo.fn = bar
        // foo.fn()
        // delete foo.fn
        // fn是对象的属性名，反正最后也要删除它，起什么都无所谓
        // 根据这个思路，我们可以尝试写第一版的call2函数
        // 第一版
        // Function.prototype.call2 = function (context) {
        //     //首先要获取调用的call函数，用this可以获取
        //     context.fn = this
        //     context.fn()
        //     delete context.fn
        // }
        // // 测试一下啊
        // var foo = {
        //     value: 1
        // }
        // function bar() {
        //     console.log(this.value)
        // }
        // bar.call2(foo)

        //模拟实现第二步
        //最开始也讲了，call函数能给定参数执行函数.举个例子
        // var foo = {
        //     value:1
        // }
        // function bar(name,age) {
        //     console.log(this.value)
        //     console.log(name,age)
        // }
        // bar.call(foo,'kiven',18)


        // arguments = {
        //     0:foo,
        //     1:'kevin',
        //     2:18,
        //     length:3
        // }
        // 因为argument是类数组

        // Function.prototype.call2 = function (context) {
        //     console.log(this)
        //     context.fn = this;
        //     context.fn();
        //     delete context.fn
        // }

        // bar.call2(foo)
        // Function.prototype.call2 = function (context) {
        //     context.fn = this;
        //     var args = [];
        //     for (var i = 1, len = arguments.length; i < len ; i++) {
        //         args.push(`arguments[${i}]`)
        //     };
        //     eval(`context.fn(${args})`);
        //     delete context.fn
        // }

        // // 测试一下啊
        // var foo = {
        //     value: 1
        // }
        // function bar(name, age) {
        //     console.log(name, age)
        //     console.log(this.value)
        // }
        // bar.call2(foo, 'mary', 18)
        // // mary 18
        // // 1
        // var foo = {
        //     value: 1
        // }

        // function bar(name, age) {
        //     return {
        //         value: this.value,
        //         name: name,
        //         age: age
        //     }
        // }

        // console.log(bar.call(foo))
        // {

        // }

        // Function.prototype.call2 = function (context) {
        //     var context = context || window;
        //     context.fn = this;

        //     var args = [];
        //     for (var i = 1, len = arguments.length; i < len; i++) {
        //         args.push(`arguments[${i}]`)
        //     };

        //     var result = eval(`context.fn(${args})`)

        //     delete context.fn

        //     return result
        // }

        // // 测试一下啊
        // var foo = {
        //     value: 1
        // };
        // var value = 2
        // function bar(name, age) {
        //     console.log(name, age)
        //     console.log(this.value)
        //     return {
        //         value: this.value,
        //         name: name,
        //         age: age
        //     }
        // };
        // bar.call2(null)
        // console.log(bar.call2(foo, 'mary', 18))
        // Function.prototype.apply1 = function (context, arr) {
        //     console.log(arr)
        //     var context = Object(context) || window;
        //     context.fn = this;

        //     var result;
        //     if (!arr) {

        //         result = context.fn();

        //     } else {
        //         var args = [];

        //         for (var i = 0, len = arr.length; i < len; i++) {
        //             args.push(`arr[${i}]`);
        //         }

        //         result = eval(`context.fn(${args})`)
        //     }
        //     delete context.fn

        //     return result
        // }
        // var foo = {
        //     value: 1
        // }
        // function bar(name, age) {
        //     console.log(this.value)
        //     return [name, age]
        // }

        // console.log(bar.apply(foo, ['mary', 18]))
        // 1
        // ['mary',18]

        // 实现call
        var obj = {
            type: 'person'
        }

        function bar(name, age) {
            console.log(this.type)
            console.log(name)
            console.log(age)
        }

        // let resObj = bar.call(obj,'lise',18)
        // console.log(resObj)
        // Function.prototype.call1 = function(context) {
        //     // 获取调用 this 的函数 
        //     context.fn = this
        //     context.fn()
        //     delete context.fn;
        // }
        // bar.call1(obj)

        // call 可以传入参数，参数不定长
        // Function.prototype.call2 = function(context) {
        //     console.log(arguments)
        //     context.fn = this
        //     var args = []
        //     let len = arguments.length
        //     for( let i = 1; i < len ; i++) {
        //         args.push('arguments[' + i + ']')
        //     }
        //     console.log(args)
        //     eval('context.fn(' + args + ')')
        //     delete context.fn
        // }
        // bar.call2(obj,1,2,3,4)

        // Function.prototype.call2 = function (context) {
        //     context = context || window
        //     context.fn = this
        //     let args = []
        //     for (let i = 1, len = arguments.length; i < len; i++) {
        //         args.push('arguments[' + i + ']')
        //     }
        //     let result = eval('context.fn(' + args + ')')
        //     delete context.fn
        //     return result
        // }
        // bar.call(obj, 'kievn', 22)

        // Function.prototype.apply1 = function (context, arr) {
        //     context.fn = this
        //     var result;
        //     // 判断有没有传值，没有就直接执行fn
        //     if (!arr) {
        //         // 将fn的返回值给result
        //         result = context.fn()
        //     } else {
        //         var args = []
        //         for (let i = 0, len = arr.length; i < len; i++) {
        //             args.push('arr[' + i + ']')
        //         }
        //         result = eval('context.fn(' + args + ')')

        //     }
        //     delete context.fn()
        //     return result
        // }

        // // 实现bind函数
        // Function.prototype.bind1 = function () {
        //     // 处理类数组
        //     const args = Array.prototype.slice.call(arguments)
        //     // 获取第一个参数
        //     const tf = args.shift()
        //     const self = this
        //     // 返回一个函数
        //     return function () {
        //         return self.apply(tf, args)
        //     }
        // }

        // // 手写深拷贝
        // function deepClone(obj) {
        //     if (typeof obj !== 'object' || obj == null) {
        //         return obj
        //     }
        //     let result = obj instanceof Array.prototype ? [] : {}
        //     for (let key in obj) {
        //         // 判断不属于这个对象原型属性
        //         if (obj.hasOwnPorperty(key)) {
        //             result[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
        //         }
        //     }
        //     return result
        // }

        // // 节流 throttle
        // function throttle(fn, wait) {
        //     var timeout = null;
        //     return function () {
        //         if (!timeout) {
        //             timeout = setTimeout(() => {
        //                 fn.apply(this, arguments)
        //                 timeout = null
        //             })
        //         }
        //     }
        // }

        // // 防抖 debounce
        // function debounce(fn, wait) {
        //     var timeout;
        //     return function () {
        //         clearTimeout(timeout)
        //         timeout = setTimeout(() => {
        //             fn.apply(this, arguments)
        //         })
        //     }
        // }

        // // 手写call
        // Function.prototype.call1 = function (context) {
        //     context = context || window
        //     context.fn = this
        //     // context.fn() 参数情况 args = ['arguments[1]']
        //     var args = []
        //     for (let i = 1, len = arguments.length; i < len; i++) {
        //         args.push('arguments[' + i + ']')
        //     }
        //     let result = eval('context.fn(' + args + ')')
        //     delete context.fn
        //     return result
        // }

        // // 手写apply
        // Function.prototype.apply2 = function (context, arr) {
        //     context = context || window
        //     context.fn = this
        //     let args = []
        //     var result;
        //     if (!arr) {
        //         result = context.fn()
        //     } else {
        //         for (let i = 0, len = arr.length; i < len; i++) {
        //             args.push('arr[' + i + ']')
        //         }
        //         result = eval('context.fn(' + args + ')')
        //     }
        //     delete context.fn
        //     return result
        // }


        // // 手写深拷贝
        // function deepClone(obj) {
        //     if (typeof obj !== 'object' || obj == null) {
        //         return obj
        //     }
        //     let result = obj instanceof Array.prototype ? [] : {}
        //     for (let key in obj) {
        //         if (obj.hasOwnPorperty(key)) {
        //             result[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
        //         }
        //     }
        //     return result
        // }


        // // 手写bind 函数
        // Function.prototype.bind2 = function () {
        //     let args = Array.prototype.slice.call(arguments)
        //     let t = args.shift()
        //     let self = this
        //     return function () {
        //         return self.apply(t, args)
        //     }

        // }

        // // 手写 call 函数
        // Function.prototype.call2 = function (context) {
        //     context = context || window
        //     context.fn = this
        //     // context.fn()
        //     let args = []
        //     for (let i = 1, len = arguments.length; i < len; i++) {
        //         args.push('argsuments[' + i + ']')
        //     }
        //     let result = eval('context.fn(' + args + ')')
        //     delete context.fn
        //     return result
        // }

        // // 手写 apply 函数
        // Function.prototype.apply2 = function (context, arr) {
        //     context = context || window
        //     context.fn = this
        //     var args = []
        //     var result;
        //     if (!arr) {
        //         result = context.fn()
        //     } else {
        //         for (var i = 0, len = arr.length; i < len; i++) {
        //             args.push('arr[' + i + ']')
        //         }
        //         result = eval('context.fn(' + args + ')')
        //     }
        //     delete context.fn
        //     return result
        // }


        // // 防抖
        // function debounce (fn, wait) {
        //     var timeout;
        //     return function () {
        //         clearTimeout(timeout)
        //         timeout = setTimeout(() => {
        //             fn.apply(this,arguments)
        //         }, wait);
        //     }
        // }

        // // 节流
        // function throttle ( fn , wait) {
        //     var timeout = null
        //     return function () {
        //         if( !timeout) {
        //             timeout = setTimeout(() => {
        //                 fn.apply(this,arguments)
        //                 timeout = null
        //             }, wait);
        //         }
        //     }
        // }


        // 实现call
        Function.prototype.call1 = function (context) {
            context = context || window
            context.fn = this
            // context.fn()
            let args = []
            for (var i = 1, len = arguments.length; i < len; i++) {
                args.push('arguments[' + i + ']')
            }
            var result = eval('context.fn(' + args + ')')
            delete context.fn
            return result
        }

        // 实现 apply
        Function.prototype.apply1 = function (context, arr) {
            context = context || window
            context.fn = this
            var result;
            var args = []
            if (!arr) {
                result = context.fn()
            } else {
                for (var i = 0, len = arr.length; i < len; i++) {
                    args.push('arr[' + i + ']')
                }
                result = eval('context.fn(' + args + ')')
            }
            delete context.fn
            return result
        }

        // 实现 bind
        Function.prototype.bind1 = function () {
            const args = Array.prototype.slice.call(arguments)
            let t = args.shift()
            let self = this
            return function () {
                return self.apply(t, args)
            }
        }

        // 深拷贝
        function deepclone(obj) {
            if (typeof obj !== 'object' || obj == null) {
                return obj
            }
            let result = obj instanceof Array.prototype ? [] : {}
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    result[key] = typeof obj[key] == 'object' ? deepclone(obj[key]) : obj[key]
                }
            }
            return result
        }

        // 防抖
        function debounce(fn, wait) {
            let timeout
            return function () {
                clearTimeout(timeout)
                timeout = setTimeout(() => {
                    fn.apply(this, arguments)
                }, wait)
            }
        }

        // 节流
        function thorttle(fn, wait) {
            let timeout = null
            return function () {
                if (!timeout) {
                    timeout = setTimeout(() => {
                        timeout = null
                        fn.apply(this, arguments)
                    },wait)
                }
            }
        }


        // 模拟call
        Function.prototype.call2 = function(context) {
            context.fn = this
            var result;
            var args = []
            for( var i = 1,len = arguments.length; i < len; i++) {
                args.push('arguments[' + i +  ']')
            }
            result = eval('context.fn('+ args + ')')
            delete context.fn
            return result
        }

        // 模拟 apply
        Function.prototype.apply1 = function(context,arr)  {
            context.fn = this
            var args= []
            var result;
            if(!arr) {
                result = context.fn()
            } else {
                for(var i = 0,len = arr.length; i < len; i++) {
                    args.push('arr[' + i + ']')
                }
                result = eval('context.fn(' + args +  ')')
            }
            delete context.fn
            return result
        }
        
        // 手写bind
        Function.prototype.bind2 = function() {
            var args = Array.prototype.slice.call(arguments)
            var t = args.shift()
            var self = this
            return function() {
                return  self.apply(t,args)
            }
        }

        // 防抖
        function debounce(fn,wait) {
            var timeout;
            return function() {
                clearTimeout(timeout)
                timeout = setTimeout(() => {
                    fn.apply(this,arguments)
                },wait)
            }
        }

        // 节流
        function thorttle(fn,wait) {
            var timeout = null
            return function() {
                if(!timeout) {
                    timeout = setTimeout(() => {
                        fn.apply(this,arguments)
                        timeout = null
                    },wait)
                }
            }
        }

        // 深拷贝
        function deppClone(obj) {
            if( typeof obj !== 'object' || obj == null) {
                return obj
            }
            let result = obj instanceof Array.prototype ? [] : {}
            for ( let key in obj) {
                if( obj.hasOwnProperty(key)) {
                    result[key] = typeof obj[key] === 'object' ? deepclone(obj[key]) : obj[key]
                }
            }
            return result
        }
        </script>
</body>

</html>